home *** CD-ROM | disk | FTP | other *** search
/ Internet Info 1994 March / Internet Info CD-ROM (Walnut Creek) (March 1994).iso / networking / ip / ka9q / alpha.arc / MBUF.C < prev    next >
C/C++ Source or Header  |  1988-07-24  |  9KB  |  443 lines

  1. /* Primitive mbuf allocate/free routines */
  2.  
  3. #include "global.h"
  4. #include "mbuf.h"
  5.  
  6. /* Allocate mbuf with associated buffer of 'size' bytes */
  7. struct mbuf *
  8. alloc_mbuf(size)
  9. register int16 size;
  10. {
  11.     register struct mbuf *bp;
  12.  
  13.     if((bp = (struct mbuf *)malloc((unsigned)(size + sizeof(struct mbuf)))) == NULLBUF)
  14.         return NULLBUF;
  15.     bp->next = bp->anext = NULLBUF;
  16.     if(size != 0){
  17.         bp->data = (char *)(bp + 1);
  18.     } else {
  19.         bp->data = NULLCHAR;
  20.     }
  21.     bp->size = size;
  22.     bp->cnt = 0;
  23.     return bp;
  24. }
  25.  
  26. /* Free all resources associated with mbuf
  27.  * Return pointer to next mbuf in packet chain
  28.  */
  29. struct mbuf *
  30. free_mbuf(bp)
  31. register struct mbuf *bp;
  32. {
  33.     register struct mbuf *bp1 = NULLBUF;
  34.  
  35.     if(bp != NULLBUF){
  36.         bp1 = bp->next;
  37.         free((char *)bp);
  38.     }
  39.     return bp1;
  40. }
  41.  
  42. /* Free packet (a chain of mbufs). Return pointer to next packet on queue,
  43.  * if any
  44.  */
  45. struct mbuf *
  46. free_p(bp)
  47. register struct mbuf *bp;
  48. {
  49.     struct mbuf *abp;
  50.  
  51.     if(bp == NULLBUF)
  52.         return NULLBUF;
  53.     abp = bp->anext;
  54.     while(bp != NULLBUF)
  55.         bp = free_mbuf(bp);
  56.     return abp;
  57. }        
  58. /* Free entire queue of packets (of mbufs) */
  59. free_q(q)
  60. struct mbuf **q;
  61. {
  62.     register struct mbuf *bp;
  63.  
  64.     while((bp = dequeue(q)) != NULLBUF)
  65.         free_p(bp);
  66. }
  67.  
  68. /* Count up the total number of bytes in an mbuf */
  69. int16
  70. len_mbuf(bp)
  71. register struct mbuf *bp;
  72. {
  73.     int cnt;
  74.  
  75.     cnt = 0;
  76.     while(bp != NULLBUF){
  77.         cnt += bp->cnt;
  78.         bp = bp->next;
  79.     }
  80.     return cnt;
  81. }
  82. /* Count up the number of packets in a queue */
  83. int16
  84. len_q(bp)
  85. register struct mbuf *bp;
  86. {
  87.     register int cnt;
  88.  
  89.     for(cnt=0;bp != NULLBUF;cnt++,bp = bp->anext)
  90.         ;
  91.     return cnt;
  92. }
  93. /* Trim mbuf to specified length by lopping off end */
  94. trim_mbuf(bpp,length)
  95. struct mbuf **bpp;
  96. int16 length;
  97. {
  98.     register int16 tot = 0;
  99.     register struct mbuf *bp;
  100.  
  101.     if(bpp == NULLBUFP || *bpp == NULLBUF)
  102.         return;    /* Nothing to trim */
  103.  
  104.     if(length == 0){
  105.         /* Toss the whole thing */
  106.         free_p(*bpp);
  107.         *bpp = NULLBUF;
  108.         return;
  109.     }
  110.     /* Find the point at which to trim. If length is greater than
  111.      * the packet, we'll just fall through without doing anything
  112.      */
  113.     for( bp = *bpp; bp != NULLBUF; bp = bp->next){
  114.         if(tot + bp->cnt < length){
  115.             tot += bp->cnt;
  116.         } else {
  117.             /* Cut here */
  118.             bp->cnt = length - tot;
  119.             free_p(bp->next);
  120.             bp->next = NULLBUF;
  121.             break;
  122.         }
  123.     }
  124. }
  125. /* Duplicate/enqueue/dequeue operations based on mbufs */
  126.  
  127. /* Duplicate first 'cnt' bytes of packet starting at 'offset'.
  128.  * This is done without copying data; only the headers are duplicated,
  129.  * but without data segments of their own. The pointers are set up to
  130.  * share the data segments of the original copy. The return pointer is
  131.  * passed back through the first argument, and the return value is the
  132.  * number of bytes actually duplicated.
  133.  */
  134. int16
  135. dup_p(hp,bp,offset,cnt)
  136. struct mbuf **hp;
  137. register struct mbuf *bp;
  138. register int16 offset;
  139. register int16 cnt;
  140. {
  141.     register struct mbuf *cp;
  142.     int16 tot;
  143.  
  144.     if(cnt == 0 || bp == NULLBUF || hp == NULLBUFP){
  145.         if(hp != NULLBUFP)
  146.             *hp = NULLBUF;
  147.         return 0;
  148.     }
  149.     if((*hp = cp = alloc_mbuf(0)) == NULLBUF){
  150.         return 0;
  151.     }
  152.     /* Skip over leading mbufs that are smaller than the offset */
  153.     while(bp != NULLBUF && bp->cnt <= offset){
  154.         offset -= bp->cnt;
  155.         bp = bp->next;
  156.     }
  157.     if(bp == NULLBUF){
  158.         free_mbuf(cp);
  159.         *hp = NULLBUF;
  160.         return 0;    /* Offset was too big */
  161.     }
  162.     tot = 0;
  163.     for(;;){
  164.         cp->data = bp->data + offset;
  165.         cp->cnt = min(cnt,bp->cnt - offset);
  166.         offset = 0;
  167.         cnt -= cp->cnt;
  168.         tot += cp->cnt;
  169.         bp = bp->next;
  170.         if(cnt == 0 || bp == NULLBUF || (cp->next = alloc_mbuf(0)) == NULLBUF)
  171.             break;
  172.         cp = cp->next;
  173.     }
  174.     return tot;
  175. }
  176. /* Copy first 'cnt' bytes of packet into a new, single mbuf */
  177. struct mbuf *
  178. copy_p(bp,cnt)
  179. register struct mbuf *bp;
  180. register int16 cnt;
  181. {
  182.     register struct mbuf *cp;
  183.     register char *wp;
  184.     register int16 n;
  185.  
  186.     if(bp == NULLBUF || cnt == 0 || (cp = alloc_mbuf(cnt)) == NULLBUF)
  187.         return NULLBUF;
  188.     wp = cp->data;
  189.     while(cnt != 0 && bp != NULLBUF){
  190.         n = min(cnt,bp->cnt);
  191.         memcpy(wp,bp->data,n);
  192.         wp += n;
  193.         cp->cnt += n;
  194.         cnt -= n;
  195.         bp = bp->next;
  196.     }
  197.     return cp;
  198. }
  199. /* Copy and delete "cnt" bytes from beginning of packet. Return number of
  200.  * bytes actually pulled off
  201.  */
  202. int16
  203. pullup(bph,buf,cnt)
  204. struct mbuf **bph;
  205. char *buf;
  206. int16 cnt;
  207. {
  208.     register struct mbuf *bp;
  209.     int16 n,tot;
  210.  
  211.     tot = 0;
  212.     if(bph == NULLBUFP)
  213.         return 0;
  214.     while(*bph != NULLBUF && cnt != 0){
  215.         bp = *bph;
  216.         n = min(cnt,bp->cnt);
  217.         if(buf != NULLCHAR && n != 0){
  218.             memcpy(buf,bp->data,n);
  219.             buf += n;
  220.         }
  221.         tot += n;
  222.         cnt -= n;
  223.         bp->data += n;
  224.         bp->cnt -= n;        
  225.         if(bp->cnt == 0){
  226.             *bph = free_mbuf(bp);
  227.         }
  228.     }
  229.     return tot;
  230. }
  231. /* Append mbuf to end of mbuf chain */
  232. void
  233. append(bph,bp)
  234. struct mbuf **bph;
  235. struct mbuf *bp;
  236. {
  237.     register struct mbuf *p;
  238.  
  239.     if(bph == NULLBUFP || bp == NULLBUF)
  240.         return;
  241.     if(*bph == NULLBUF){
  242.         /* First one on chain */
  243.         *bph = bp;
  244.     } else {
  245.         for(p = *bph ; p->next != NULLBUF ; p = p->next)
  246.             ;
  247.         p->next = bp;
  248.     }
  249. }
  250. /* Insert specified amount of contiguous new space at the beginning of an
  251.  * mbuf chain. If enough space is available in the first mbuf, no new space
  252.  * is allocated. Otherwise a mbuf of the appropriate size is allocated and
  253.  * tacked on the front of the chain.
  254.  *
  255.  * This operation is the logical inverse of pullup(), hence the name.
  256.  */
  257. struct mbuf *
  258. pushdown(bp,size)
  259. register struct mbuf *bp;
  260. int16 size;
  261. {
  262.     register struct mbuf *nbp;
  263.  
  264.     /* Check that bp is real and that there's data space associated with
  265.      * this buffer (i.e., this is not a buffer from dup_p) before
  266.      * checking to see if there's enough space at its front
  267.      */
  268.     if(bp != NULLBUF && bp->size != 0 && bp->data - (char *)(bp+1) >= size){
  269.         /* No need to alloc new mbuf, just adjust this one */
  270.         bp->data -= size;
  271.         bp->cnt += size;
  272.     } else {
  273.         if((nbp = alloc_mbuf(size)) != NULLBUF){
  274.             nbp->next = bp;
  275.             nbp->cnt = size;
  276.             bp = nbp;
  277.         } else {
  278.             bp = NULLBUF;
  279.         }
  280.     }
  281.     return bp;
  282. }
  283. /* Append packet to end of packet queue */
  284. void
  285. enqueue(q,bp)
  286. struct mbuf **q;
  287. struct mbuf *bp;
  288. {
  289.     register struct mbuf *p;
  290.     char i_state;
  291.  
  292.     if(q == NULLBUFP || bp == NULLBUF)
  293.         return;
  294.     i_state = disable();
  295.     if(*q == NULLBUF){
  296.         /* List is empty, stick at front */
  297.         *q = bp;
  298.     } else {
  299.         for(p = *q ; p->anext != NULLBUF ; p = p->anext)
  300.             ;
  301.         p->anext = bp;
  302.     }
  303.     restore(i_state);
  304. }
  305. /* Unlink a packet from the head of the queue */
  306. struct mbuf *
  307. dequeue(q)
  308. register struct mbuf **q;
  309. {
  310.     register struct mbuf *bp;
  311.     char i_state;
  312.  
  313.     if(q == NULLBUFP)
  314.         return NULLBUF;
  315.     i_state = disable();
  316.     if((bp = *q) != NULLBUF){
  317.         *q = bp->anext;
  318.         bp->anext = NULLBUF;
  319.     }
  320.     restore(i_state);
  321.     return bp;
  322. }    
  323.  
  324. /* Copy user data into an mbuf */
  325. struct mbuf *
  326. qdata(data,cnt)
  327. char *data;
  328. int16 cnt;
  329. {
  330.     register struct mbuf *bp;
  331.  
  332.     if((bp = alloc_mbuf(cnt)) == NULLBUF)
  333.         return NULLBUF;
  334.     memcpy(bp->data,data,cnt);
  335.     bp->cnt = cnt;
  336.     return bp;
  337. }
  338. /* Copy mbuf data into user buffer */
  339. int16
  340. dqdata(bp,buf,cnt)
  341. struct mbuf *bp;
  342. char *buf;
  343. unsigned cnt;
  344. {
  345.     unsigned n,tot;
  346.     struct mbuf *bp1;
  347.  
  348.     if(buf == NULLCHAR)
  349.         return 0;
  350.     
  351.     tot = 0;
  352.     for(bp1 = bp;bp1 != NULLBUF; bp1 = bp1->next){
  353.         n = min(bp1->cnt,cnt);
  354.         memcpy(buf,bp1->data,n);
  355.         cnt -= n;
  356.         buf += n;
  357.         tot += n;
  358.     }
  359.     free_p(bp);
  360.     return tot;
  361. }
  362. /* Pull a 32-bit integer in host order from buffer in network byte order */
  363. int32
  364. pull32(bpp)
  365. struct mbuf **bpp;
  366. {
  367.     int32 rval;
  368.     char buf[4];
  369.     register char *cp;
  370.  
  371.     if(pullup(bpp,buf,4) != 4){
  372.         /* Return zero if insufficient buffer */
  373.         return 0;
  374.     }
  375.     cp = buf;
  376.  
  377.     /* Unwound for speed */
  378.     rval = uchar(*cp++);
  379.     rval <<= 8;
  380.     rval |= uchar(*cp++);
  381.     rval <<= 8;
  382.     rval |= uchar(*cp++);
  383.     rval <<= 8;
  384.     rval |= uchar(*cp);
  385.  
  386.     return rval;
  387. }
  388. /* Pull a 16-bit integer in host order from buffer in network byte order */
  389. int16
  390. pull16(bpp)
  391. struct mbuf **bpp;
  392. {
  393.     int16 rval;
  394.     char buf[2];
  395.     register char *cp;
  396.  
  397.     if(pullup(bpp,buf,2) != 2){
  398.         /* Return zero if insufficient buffer */
  399.         return 0;
  400.     }
  401.     cp = buf;
  402.  
  403.     rval = uchar(*cp++);
  404.     rval <<= 8;
  405.     rval |= uchar(*cp);
  406.     return rval;
  407. }
  408. /* Pull single character from mbuf */
  409. char
  410. pullchar(bpp)
  411. struct mbuf **bpp;
  412. {
  413.     char c;
  414.  
  415.     if(pullup(bpp,&c,1) != 1)
  416.         /* Return zero if nothing left */
  417.         c = 0;
  418.     return c;
  419. }
  420. /* Put a long in host order into a char array in network order */
  421. char *
  422. put32(cp,x)
  423. register char *cp;
  424. int32 x;
  425. {
  426.     *cp++ = x >> 24;
  427.     *cp++ = x >> 16;
  428.     *cp++ = x >> 8;
  429.     *cp++ = x;
  430.     return cp;
  431. }
  432. /* Put a short in host order into a char array in network order */
  433. char *
  434. put16(cp,x)
  435. register char *cp;
  436. int16 x;
  437. {
  438.     *cp++ = x >> 8;
  439.     *cp++ = x;
  440.  
  441.     return cp;
  442. }
  443.